<template>
  <div class="BimIntegrate-container layout">
    <div v-if="state.loading" class="layout-loading-process">
      <a-progress type="circle" :percent="state.percent" />
    </div>
    <div v-show="isEmptyModel || visibleState.isEmpty" class="empty-container">
      <a-empty description="未检测到模型" />
    </div>
    <div v-show="!isEmptyModel" class="layout-container">
      <canvas id="View" class="lay-wrap" style="width: 100%; height: 100%" />
      <tool-bar class="tool-bar" v-bind="$attrs" :check-selected-fn="checkToolSelected"
                v-if="state.floors && state.floors.children && state.floors.children.length"
                @setThumbtack="setThumbtack"
                @resetTumbtack="resetTumbtack"
                :excludeTool="excludeTool"
                :update-selected-fn="updateToolSelected" />
      <div class="extra-wrapper">
        <!-- 漫游的速度调节器 -->
        <div v-if="checkToolSelected('roaming', 1)" class="roaming-speed-wrapper">
          <span class="speed-label">移动速度</span>
          <a-slider class="speed-value" :default-value="state.roamSpeed" :max="20" @change="updateRoamingSpeed" />
        </div>
      </div>
    </div>
    <!-- 结构信息窗口 -->
    <ControlTree
      class="side-left"
      :domains="state.domains"
      :floors="state.floors"
      :selected-domains="state.selectedDomains"
      :selected-floors="state.selectedFloors"
      :loading="loadingState.updateTree"
      :modelTitle="modelList[0] && modelList[0].modelTitle"
      v-bind="$attrs"
      @showCurSelectTreeNode="showCurSelectTreeNode"
      @highlightTreeNode="highlightTreeNode"
      @unHighlightTreeNode="unHighlightTreeNode"
      v-on="$listeners"
    />
    <!-- 属性信息窗口 -->
    <AttributeTab v-if="visibleState.attrVisible" class="side-right" :bim-data="state.currentData" :uuid="state.uuid" @close="visibleState.attrVisible = false" />
    <!-- 设置弹窗 -->
    <move-model v-if="visibleState.settingVisible" :settings="state.setParms" @modal:cancel="visibleState.settingVisible = false" @modal:ok="handleSettingOk" />
    <!-- 版本信息弹窗 -->
    <switch-version
      v-if="visibleState.versionVisible"
      :model-version="this.modelVersion"
      :model-id="this.modelId"
      @cancel="
        () => {
          updateVisible('versionVisible', false)
        }
      "
      @switch:version="handleVersionChanged"
    />
    <!-- 构件搜索窗口 -->
    <construct-search
      v-if="visibleState.searchVisible"
      :model-id="modelId"
      :modelList="modelList"
      @cancel="
        () => {
          updateVisible('searchVisible', false)
        }
      "
      @search:ok="handleSearchOk"
    />
    <!-- 搜索结果窗口 -->
    <search-result v-if="visibleState.resultVisible" :init-list="resultList" @cancel="visibleState.resultVisible = false" @backSearch="handleBacksearch" @position="handlePosition" />
    <!-- 右键菜单 -->
    <a-menu
      v-if="visibleState.contextMenu"
      class="context-menu-container"
      :style="{
        left: menuPosition.pageX + 'px',
        top: menuPosition.pageY + 'px'
      }"
      mode="vertical"
      @select="handleContextMenuAction"
    >
      <template v-for="menu in contextMenuList">
        <a-sub-menu v-if="menu.children && menu.children.length" :key="menu.type" :title="menu.name" popup-class-name="contextSubmenu">
          <a-menu-item v-for="item in menu.children" :key="item.name">
            {{ item.name }}
          </a-menu-item>
        </a-sub-menu>
        <a-menu-item v-else :key="menu.type">
          {{ menu.name }}
        </a-menu-item>
      </template>
    </a-menu>
    <!-- 分享窗口 -->
    <ShareModel :visible.sync="visibleState.shareVisible" :modelList="modelList" />
<!--    图钉窗口-->
    <Thumbtack :drawVisible.sync="drawVisible"
               :treeData="treeData"
               ref="thumbtackRefs"
               :setThumb="setThumb"
               @select="clickThumbtack"
              ></Thumbtack>
    <img src="../../assets/icons/tuding.png"
         alt="图钉" class="thumbtackImg"
         v-if="showIcon"
         title="图钉"
         @click="drawVisible=true">
  </div>
</template>

<script>
import { menuBlock } from './menuConfig.js'
import { modelConfig } from './websiteConfig.js'
import { getHistory, getAllComponents, getFloorsList, getDominsList } from '@/api/bimIntegrate'
import { getBimThumbtackByModelId } from '@/api/bimIntegrate/bimModel'
import Thumbtack from './components/Thumbtack'
import { validateToken } from '@/api/bimIntegrate/request'
import SearchResult from './components/SearchResult'
import ConstructSearch from './components/ConstructSearch'
import SwitchVersion from './components/SwitchVersion'
import AttributeTab from './components/AttributeTab'
import ControlTree from './components/ControlTree'
import MoveModel from './components/MoveModel'
import ToolBar from './components/ToolBar'
import ShareModel from './components/ShareModel'


import characterdat from './resource/character.dat'
import characterpng from './resource/character.png'
import new_front_chinese from './resource/front_chinese.png'
import new_back_chinese from './resource/back_chinese.png'
import new_left_chinese from './resource/left_chinese.png'
import new_right_chinese from './resource/right_chinese.png'
import new_top_chinese from './resource/top_chinese.png'
import new_bottom_chinese from './resource/bottom_chinese.png'
import new_compass_plate_chinese from './resource/compass_chinese.png'
const secure = require('./resource/secure.png')
const quality =  require('./resource/quality.png')
import { walkTree } from './utils.js'
import { Empty, Slider } from 'ant-design-vue'

const FLOOR_TREE = 'FLOOR_TREE'
const DOMAIN_TREE = 'DOMAIN_TREE'

const WINDData = window.WIND && window.WIND.WINDData
const WINDView = window.WIND && window.WIND.WINDView

export default {
  components: {
    ToolBar,
    MoveModel,
    ControlTree,
    AttributeTab,
    SwitchVersion,
    ConstructSearch,
    SearchResult,
    AEmpty: Empty,
    ASlider: Slider,
    ShareModel,
    Thumbtack
  },
  props: {
    modelId: {
      type: String,
      default: ''
    },
    // 同时打开多个模型时传入参数 Array<Object>：[{ modelId: String, version: Number }]
    modelList: {
      type: Array,
      default() {
        return []
      }
    },
    // 是否显示图钉
    showPushPin: {
      type: Boolean,
      default: false
    },
    // 需要展示的图钉列表
    pushpinList: {
      type: Array,
      default() {
        return []
      }
    },
    // 默认选中楼层树节点
    defaultSelectedFloors: {
      type: Array,
      default() {
        return []
      }
    },
    // 选中所有树节点
    showAllNode: {
      type: Boolean,
      default: true
    },
    // 是否可点击
    clickable: {
      type: Boolean,
      default: true
    },
    highLightList: {
      // 需要高亮的实体列表
      type: String,
      default: ''
    },
  },
  data() {
    return {
      isModelParameterLoaded: false,
      excludeTool: [], //不显示的图标工具
      drawVisible: false, //图钉面板开关
      showIcon: false,
      treeData: [],
      visibleState: {
        isEmpty: false, // 空数据
        attrVisible: false, // 属性信息面板
        settingVisible: false, // 设置弹窗
        resultVisible: false, // 搜索结果弹窗
        searchVisible: false, // 搜索弹窗
        versionVisible: false, // 版本信息弹窗
        contextMenu: false, // 右键菜单
        shareVisible: false // 分享
      },
      toolTreeData: [], // 工具菜单数据
      loadingState: {
        updateTree: false
      },
      isInitedVersion: false, // 是否已初始版本
      modelVersion: 1, // 模型版本，默认为1
      contextMenuOptions: {
        none: [
          {
            name: '显示全部构件',
            type: 'showAllComponents'
          }
        ],
        single: [
          {
            name: '查看构件属性',
            type: 'showProperty'
          },
          {
            name: '显示全部',
            type: 'showAll'
          },
          {
            name: '隐藏选中',
            type: 'hiddenSelected'
          },
          {
            name: '隔离选中',
            type: 'insulateSelected'
          }
        ]
      },
      menuPosition: {
        pageX: 0,
        pageY: 0
      },
      resultList: [],
      state: {
        loading: false,
        percent: 0, // 模型加载百分比
        currentData: null, // 当前模型的数据对象
        currentView: null, // 当前模型的视图对象
        floors: null, // 楼层数据
        domains: null, // 专业数据
        selectedFloors: null,
        selectedDomains: null,
        entities: [], // 所选中的实体
        roamSpeed: 4, // 漫游速度
        setParms: {}, // 光照、背景等相关设置属性的对象集合
      },
      selectedFloorsObj:[],
      init: false,
      originFloor: [], //原始楼层数据
      originDomins: [], // 原始构件数据
      bimThumbtackByModelList: {

      }, // 图钉相关数据
      uuIds: [] //图钉uuIds
    }
  },
  computed: {
    contextMenuList() {
      const { entities } = this.state
      return entities.length === 0 ? this.contextMenuOptions['none'] : this.contextMenuOptions['single']
    },
    isEmptyModel() {
      return !this.modelId && !this.modelList?.length
    }
  },
  watch: {
    modelId: {
      handler(val) {
        this.initPage()
      }
    },
    pushpinList: {
      handler(val) {
        this.initPushPin()
      }
    },
    defaultSelectedFloors: {
      deep: true,
      handler(val) {
        if (!this.init && val.length && this.state.floors.children?.length) {
          this.init = true
          view.getWINDViewControl().hideTreeRoot(this.state.floors)
          this.$nextTick(() => {
            const list = []
            this.flatFloor(this.state.floors, list)
            for (let i of this.defaultSelectedFloors) {
              !list.find((t) => t.id === i)?.children?.length && view.getWINDViewControl().displayTreeNode(i, this.state.floors)
            }
          })
        }
      }
    }
  },
  async mounted() {
    if(!sessionStorage.getItem("bimToken")) {
    await validateToken()
    }
    if(this.$route.query.isModelList == 1) {
      this.excludeTool = []
      this.getBimThumbtackByModelId()
    } else {
      this.excludeTool = ['thumbtack']
    }

    this.initToolTree()
    this.initPage()
  },
  beforeDestroy() {
    this.destroyModel()
  },
  methods: {
    // 获取图钉信息
    getBimThumbtackByModelId() {
      let id = this.$route.query.id
      if(!id) return
      getBimThumbtackByModelId({ id }).then(res=>{
        this.bimThumbtackByModelList = res.data
        this.createTree()
      })
    },
    // 创建图钉树结构
    createTree() {
      this.bimThumbtackByModelList.safeDTO.checked = true
      this.bimThumbtackByModelList.safeDTO.nodeTiile = '安全管理问题'
      this.bimThumbtackByModelList.safeDTO.nodeName = '安全管理问题' + '('+this.bimThumbtackByModelList.safeDTO.totalNum+')'
      this.bimThumbtackByModelList.safeDTO.id = '安全管理问题0'
      this.bimThumbtackByModelList.safeDTO.scopedSlots = {title: 'title'}
      this.createIds(this.bimThumbtackByModelList.safeDTO.safeDetails)

      this.bimThumbtackByModelList.qualityDTO.checked = true
      this.bimThumbtackByModelList.qualityDTO.nodeTiile = '质量管理问题'
      this.bimThumbtackByModelList.qualityDTO.nodeName = '质量管理问题'+ '(' + this.bimThumbtackByModelList.qualityDTO.totalNum+')'
      this.bimThumbtackByModelList.qualityDTO.id = '质量管理问题0'
      this.bimThumbtackByModelList.qualityDTO.scopedSlots = {title: 'title'}
      this.createIds(this.bimThumbtackByModelList.qualityDTO.qualityDetails)

      this.bimThumbtackByModelList.safeDTO.children =  this.bimThumbtackByModelList.safeDTO.safeDetails
      this.bimThumbtackByModelList.qualityDTO.children =  this.bimThumbtackByModelList.qualityDTO.qualityDetails
      this.treeData = [this.bimThumbtackByModelList.safeDTO, this.bimThumbtackByModelList.qualityDTO]
    },
    // 选中图钉回调
    setThumb(treeData) {
      this.uuIds = this.setUuIds(treeData)
      const { currentView } = this.state
      const viewPushpin = currentView.getWINDViewPushpin() // 获取图钉实例
      currentView.getWINDViewControl().unhighlightAllEntities()
      viewPushpin.deleteAllPushpin()
      this.showPushpin(this.uuIds)
    },
    // 选择项变化时，重新设置uuid
    setUuIds(data) {
      let arr = []
      data.forEach(item=>{
        if(item.bimId&& this.$refs.thumbtackRefs.checkedKeys.includes(item.id)) {
          let uid = item.bimId.split('&&&&')[1]
          let obj = {
            uid,
            businessType: item.businessType,
            businessId: item.businessId
          }

          arr.push(obj)
        }
        if(item.children&&item.children.length) {
          arr = arr.concat(this.setUuIds(item.children))
        }
      })
      return arr
    },
    createIds(data) {
      data.forEach((item,i) => {
        item.id = item.nodeName + i
        item.scopedSlots = {title: 'title'}
        if(item.children&&item.children.length) {
          this.createIds(item.children)
        }
      })
    },
    //点击图钉图标 获取选中图钉uuid
    getUuIds(data) {
      data.forEach((item,i) => {
        if(item.bimId) {
          let uid = item.bimId.split('&&&&')[1]
          let obj = {
            uid,
            businessType: item.businessType,
            businessId: item.businessId
          }
          this.uuIds.push(obj)
        }
        if(item.children&&item.children.length) {
          this.getUuIds(item.children)
        }
      })
    },
    //显示图钉
    showPushpin(uuIds) {
      const { currentView, currentData } = this.state
        const viewPushpin = currentView.getWINDViewPushpin() // 获取图钉实例
        // 开启图钉
        viewPushpin.openPushpin()
        uuIds.forEach((item,index)=>{
          viewPushpin.createPushpin(item.uid,[item.uid],{
            imageSrc: (item.businessType==1 || item.businessType == 2) ? secure : quality,
            width: 30,
            height: 44,
            userData: item
          })

          this.highlightNodeByIds(item.uid)
        })
      viewPushpin.showAllPushpin()
        viewPushpin.setPushpinCallback((id, event, userdata) => {
          if (event === 3) {
            currentView.getWINDViewControl().untransparentAllComponents()
            this.jump(userdata)
          }
        })
    },
    //重置图钉
    resetTumbtack() {
      this.$refs.thumbtackRefs.checkedKeys = []
      const { currentView } = this.state
      const viewPushpin = currentView.getWINDViewPushpin() // 获取图钉实例
      viewPushpin.closePushpin()
      viewPushpin.deleteAllPushpin()
      this.unHighlightTreeNode()
    },
    // 设置图钉
    setThumbtack(vals) {
      if(vals.length === 0) return
      this.resetTumbtack()
      this.showIcon = true
      this.drawVisible = true
      let arr = []
      let dataArr = []
      this.treeData.forEach(item=>{
        if(vals.includes(item.nodeTiile)) {
          arr.push(item.id)
          dataArr.push(item)
        }
      })
      this.$refs.thumbtackRefs.checkedKeys = arr
      this.uuIds = []
      this.getUuIds(dataArr)
      this.showPushpin(this.uuIds)
    },
    //点击图钉弹窗节点 跳转至对应业务详情
    clickThumbtack(data) {
      if(data.bimId) {
      let uid = data.bimId.split('&&&&')[1]
      let obj = {
        uid,
        businessType: data.businessType,
        businessId: data.businessId
      }
        this.jump(obj)
      }
    },
    // 跳转至对应业务详情
    jump(userdata) {
      if(userdata.businessType == 1) { //危险源
        this.$router.push({
          path: '/safetySupervision/hazardIdentification/safetyAddConference',
          query: {
            id: userdata.businessId,
            pageType: 'look'
          }
        })
      } else if(userdata.businessType == 2) { //检查记录
        this.$router.push({
          path: '/safetySupervision/checkAndRectify/checkRecord/detail',
          query: {
            id: userdata.businessId,
            pageType: 'look'
          }
        })
      } else if(userdata.businessType == 3) { //质量检查
        this.$router.push({
          path: '/quality/newRecordInfo',
          query: {
            id: userdata.businessId,
            qualityInspectionRecord: true
          }
        })
      } else if(userdata.businessType == 4) { //实测实量
        this.$router.push({
          path: '/quality/measuredAmount/deskAccount/deskAccountEdit',
          query: {
            id: userdata.businessId,
            editModel: 2
          }
        })
      }
    },
    /**
     * @description: 扁平化数据
     * @param {*} list：需要扁平化的数据
     * @param {*} arr：扁平化后的数据
     * @return {*}
     */
    flatFloor(list, arr) {
      list.forEach((item) => {
        if (!arr.length || arr.every((i) => i.id !== item.id)) {
          arr.push(item)
        }
        if (item.children) {
          this.flatFloor(item.children,arr)
        }
      })
    },
    /**
     * 更新visibleState里的值
     * @param {String} key -键名
     * @param {Boolean} value -更新值
     * @param {Boolean} isSwitch -是否反转值
     */
    updateVisible(key, value, isSwitch = false) {
      if (isSwitch) {
        this.visibleState[key] = !this.visibleState[key]
      } else {
        this.visibleState[key] = value
      }
    },
    /**
     * 给构件批量上色
     * @param {Array<String>} uuidList -构件的uuid数组
     * @param {Array<Number>} colorList -颜色数组 eg: [red, green, blue, alpha] 所有值均为0-255
     * @returns {Boolean} 成功true，失败false
     */
    coloringComponents(uuidList, colorList) {
      const { currentView } = this.state
      const control = currentView.getWINDViewControl()
      const batchId = 'colorBatchId'
      control.createBatchEntities(batchId, uuidList)
      return control.coloringBatchEntities(batchId, ...colorList)
    },
    /**
     * 对部分构件运用动画切割生长
     * @param {Array<String>} uuidList -构件的uuid数组
     * @param {Object} options -配置项：step每次动画回调的加载跨度，time动画执行总时长，callback动画执行的回调
     * @returns {Object} -视图控制对象，可调用pauseAnimation：暂停动画，goonAnimation()继续动画，gotoAnimation(time)动画跳转到指定时间点
     */
    startAnimationByPart(uuidList, { step, time, callback } = {}) {
      const { currentView } = this.state
      const control = currentView.getWINDViewControl()
      const batchIdClip = 'clipId'
      control.createBatchEntities(batchIdClip, uuidList)
      control.setClippingGrowBatchEntities(batchIdClip, 2)
      let radio = 0
      const stepNum = step || 0.01
      const timeLength = time || (1 / stepNum) * 120
      const callbackFn = callback
        ? callback
        : (time) => {
            radio += stepNum
            control.applyGrowBatchEntities(batchIdClip, radio)
          }
      currentView.startAnimation(timeLength, callbackFn)
      return control
    },
    /**
     * 对整个模型运用动画切割生长
     * @param {Object} -配置项，同startAnimationByPart函数
     */
    async starAnimationByAll(options = {}) {
      const { currentData } = this.state
      // getAllStoreyParameterL: 获取楼层信息；getAllComponentParameterL：获取构件信息
      const res = await currentData.getWINDDataQuerier().getAllComponentParameterL()
      const uuidList = res.reduce((pre, cur) => pre.concat(cur.parameter), []).map((item) => item.uuid)
      return this.startAnimationByPart(uuidList, options)
    },
    async handleTest() {
      this.starAnimationByAll()
    },
    /**
     * 初始化工具栏的数据结构
     */
    initToolTree() {
      const originTree = JSON.parse(JSON.stringify(menuBlock))
      walkTree(originTree, {
        resolveNodeFn: (node) => {
          node.key = node.selected
          node.selected = false
        }
      })
      this.toolTreeData = originTree
    },
    /**
     * 更新tool按钮的选中状态（将选中状态置反）
     * @param {String} key -按钮标识
     * @param {Number} level -按钮所处层级
     * @param {String} parentKey -父节点Key
     */
    updateToolSelected(key, level, { parentKey } = {}) {
      // 更新选中状态
      this.updateTreeSelected(key, level)
      // 更新完状态后执行相关操作
      if (level === 1) {
        // this.starAnimationByAll()
        this.selectMenu(key)
      }
      if (level === 2) {
        const map = {
          roaming: () => {
            this.onClickRoam(key)
          },
          measure: () => {
            this.onClickMeasure(key)
          }
        }
        // 父节点
        const parentNode = this.checkToolSelected(parentKey, level - 1, true)
        // 是否有兄弟节点被选中
        const siblingSelected = parentNode.children.some((item) => !!item.selected)
        // 当前节点
        const currentNode = parentNode.children.find((item) => item.key === key)
        // 如果当前节点处于选中状态，且父节点未被选中，那么先选中父节点，再调用相关事件
        if (currentNode.selected && !parentNode.selected) {
          this.updateToolSelected(parentKey, level - 1)
          map[parentKey] && map[parentKey]()
        }
        // 如果当前节点未选中，且所有兄弟节点均未被选中，那么在调用相关事件后，需要重置一下父节点状态
        else if (!currentNode.selected && !siblingSelected) {
          map[parentKey] && map[parentKey]()
          this.updateToolSelected(parentKey, level - 1)
        } else {
          // 否则直接调用相关事件即可
          map[parentKey] && map[parentKey]()
        }
      }
    },
    /**
     * 更新树选中状态
     * @param {String} key -按钮标识
     * @param {Number} level -按钮所处层级
     */
    updateTreeSelected(key, level) {
      walkTree(this.toolTreeData, {
        resolveNodeListFn: (nodeList, listLevel) => {
          if (listLevel === level) {
            const target = nodeList.find((item) => item.key === key)
            if (target) {
              target.selected = !target.selected
              if (!target.selected) {
                target.children &&
                  target.children.forEach((childItem) => {
                    childItem.selected = false
                  })
              }
            }
            return true
          }
        }
      })
    },
    /**
     * 返回指定key值按钮的选中状态
     * @param {String} key -按钮标识
     * @param {Number} level -按钮所处层级
     * @param {Boolean} returnNode -是否返回node节点
     */
    checkToolSelected(key, level, returnNode = false) {
      let selected = false
      let nodeData = null
      walkTree(this.toolTreeData, {
        resolveNodeFn: (node, nodeLevel) => {
          if (level === nodeLevel && key === node.key) {
            selected = !!node.selected
            nodeData = node
            return true
          }
        }
      })
      return returnNode ? nodeData : selected
    },
    initPage() {
      this.$nextTick(() => {
        if (this.isEmptyModel) {
          this.$message.warning('未检测到模型，请返回重试')
          return
        }
        this.loadModel()
      })
    },
    /**
     * 初始化图钉
     */
    initPushPin() {
      if (!this.showPushPin || !this.pushpinList.length) return
      const pinList = this.pushpinList
      const { currentView, pushpin } = this.state
      if (!currentView) return
      if (!pushpin) {
        this.state.pushpin = currentView.getWINDViewPushpin()
      }
      const curPushpin = this.state.pushpin
      curPushpin.hideAllPushpin()
      const pushpinState = curPushpin.getPushpinState()._pushpinOpened
      if (pushpinState) {
        this.unHighlightTreeNode()
        // 图钉处于开启时，将图钉关闭
        curPushpin.closePushpin()
      }
      curPushpin.openPushpin()
      const partIds = pinList.reduce((pre, cur) => {
        return cur.ids ? pre.concat(cur.ids) : pre
      }, [])
      this.highlightTreeNode(partIds, true) // 高亮图钉的构件区域
      curPushpin.deleteAllPushpin()
      // 新增图钉
      pinList.forEach((item, index) => {
        let img = ''
        try {
          img = require(`./resource/pushpin/icon_topic_${item.status}.png`)
        } catch {
          img = require(`./resource/pushpin/icon_topic_finish.png`)
        }
        // 用索引作为图钉id
        curPushpin.createPushpin(index.toString(), item.ids, {
          imageSrc: img,
          width: 35,
          height: 50
        })
      })
      // 设置图钉回调
      curPushpin.setPushpinCallback((id, event, userdata) => {
        if (event === 3) {
          // 点击事件
          const targetData = this.pushpinList[id] // 创建图钉时使用的索引，所以此处获取的图钉ID实际为图钉列表的索引
          this.$emit('clickPushpin', targetData)
        }
      })
      curPushpin.showAllPushpin()
    },
    // 复原图钉
    revertPushpin(list) {
      const { pushpin } = this.state
      pushpin &&
        list.forEach((item, index) => {
          pushpin.revertPushpin(index.toString())
        })
    },
    // 图钉操作
    handlePushpin() {
      const { pushpin, currentView, entities } = this.state
      if (!pushpin) {
        this.state.pushpin = currentView.getWINDViewPushpin()
      }
      const curPushpin = this.state.pushpin
      const pushpinState = curPushpin.getPushpinState()._pushpinOpened
      if (pushpinState) {
        // 图钉处于开启时，将图钉关闭
        pushpin.closePushpin()
        return
      }
      curPushpin.openPushpin()
      const entry = entities[0]
      curPushpin.createPushpin(entry, entities, {
        imageSrc: require('./resource/pushpin/pin.png'),
        width: 30,
        height: 40
      })
      curPushpin.setPushpinCallback((id, event, userdata) => {
        if (event === 3) {
          this.$message.info('点击图钉')
        }
      })
      curPushpin.showAllPushpin()
    },
    // 处理右键菜单项事件
    handleContextMenuAction({ key }) {
      const type = key
      const { currentView, entities } = this.state
      const actionMap = {
        showAllComponents: () => {
          currentView && currentView.getWINDViewControl().showAllComponents()
        },
        showProperty: () => {
          this.updateVisible('attrVisible', true)
        },
        showAll: () => {
          currentView && currentView.getWINDViewControl().showAllComponents()
          currentView && currentView.getWINDViewControl().highlightAssignedEntities(entities) // 高亮模块
        },
        hiddenSelected: () => {
          currentView && currentView.getWINDViewControl().hideSelectComponents()
        },
        insulateSelected: () => {
          currentView && currentView.getWINDViewControl().hideUnselectComponents()
        }
      }
      actionMap[type] && actionMap[type]()
      this.visibleState.contextMenu = false
    },
    // 高亮
    highlightNodeByIds(ids) {
      const { currentView } = this.state
      currentView?.getWINDViewControl().highlightAssignedEntities(ids)
      currentView?.getWINDViewRoaming().locateSelectEntities() // 定位到高亮的实体
    },
    // 搜索结果里定位操作的实现
    handlePosition(data) {
      const { ids } = data
      this.mainView() // 复位相机
      this.unHighlightTreeNode()
      const { currentView } = this.state
      currentView.getWINDViewControl().transparentAllComponents() // 透明构件
      currentView.getWINDViewControl().unhighlightAllEntities() // 取消所有高亮
      currentView.getWINDViewControl().highlightAssignedEntities(ids) // 高亮实体
      currentView.getWINDViewRoaming().locateSelectEntities() // 定位至高亮实体处
    },
    // 版本切换，重新加载新版本模型
    handleVersionChanged(data) {
      this.updateVersion('versionVisible', false)
      this.modelVersion = data.version
      this.loadModel()
    },
    // 返回搜索框
    handleBacksearch() {
      this.updateVisible('searchVisible', true)
      this.updateVisible('resultVisible', false)
    },
    // 搜索完成的回调
    handleSearchOk(list) {
      this.resultList = list
      this.updateVisible('searchVisible', false)
      this.updateVisible('resultVisible', true)
    },
    // 设置完成的回调
    handleSettingOk(data) {
      this.onClickSetting(data)
      this.updateVisible('settingVisible', false)
      this.state.setParms = data
    },
    /**
     * 设置state里数据
     */
    setState(state, fn) {
      this.state = {
        ...this.state,
        ...state
      }
      if (fn) {
        this.$nextTick(() => {
          fn()
        })
      }
    },
    // 销毁模型
    destroyModel() {
      const { currentData } = this.state
      if (currentData) {
        currentData.getWINDDataLoader().closeAllModelDatas()

        this.state.pushpin = null // 重置图钉
      }
    },
    // 加载模型
    async loadModel() {
      if (this.isEmptyModel) return
      // 防止之前的模型数据未清除
      this.destroyModel()
      // WINDData初始化
      let data, view, config
      let floorTree = { YZTreeType: FLOOR_TREE }
      let domainTree = { YZTreeType: DOMAIN_TREE }

      // 模型服务器设置
      config = Object.assign({}, modelConfig)

      // WINDView初始化
      let canvas = document.querySelector('#View')

      data = new WINDData(config)
      view = new WINDView(canvas)
      this.state = {
        ...this.state,
        loading: false,
        percent: 0
      }

      // 数据加载执行回调
      data.addWINDDataCallback(1, (type, option) => {
        this.updateDataNode(type, option)
      })

      // 视图加载执行回调
      view.addWINDViewCallback(1, (type, option) => {
        if (!this.init && this.defaultSelectedFloors.length && option.children?.length) {
          this.init = true
          view.getWINDViewControl().hideTreeRoot(this.state.floors)
          this.$nextTick(() => {
            const list = []
            this.flatFloor([option], list)
            for (let i of this.defaultSelectedFloors) {
              !list.find((t) => t.id === i)?.children?.length && view.getWINDViewControl().displayTreeNode(i, this.state.floors)
            }
          })
        }
        if (this.modelList?.[0]?.uuId) {
          this.highlightNodeByIds(this.modelList[0].uuId)
        }
        this.getCurrentViewData(type, option)
        this.updateTreeNode(type, option)
      })

      //设置控制树显示规则类型
      let floorTypes = [window.WIND.TreeRuleType.PROJECT_NAME, window.WIND.TreeRuleType.STOREY_NAME]
      let domainTypes = [window.WIND.TreeRuleType.DOMAIN_NAME, window.WIND.TreeRuleType.CATEGORY_NAME, window.WIND.TreeRuleType.TYPE_NAME, window.WIND.TreeRuleType.COMPONENT_UNIQUEID]
      //创建构件显示控制树
      view.getWINDViewControl().createComponentTree(floorTypes, floorTree)
      view.getWINDViewControl().createComponentTree(domainTypes, domainTree)
      view.bindWINDData(data)

      //设置模型视图背景颜色
      let color = [255, 255, 255, 255]
      view.getWINDViewSetting().setBackgroundPureColor(color[0], color[1], color[2], color[3])
      //设置导航辅助六个面显示的图片
      view.getWINDViewAssist().setNavigateResource(new_front_chinese, new_back_chinese, new_top_chinese, new_bottom_chinese, new_left_chinese, new_right_chinese, new_compass_plate_chinese)
      //开启导航辅助
      view.getWINDViewAssist().setNavigateProperty(20, 0, 120)
      view.getWINDViewAssist().openNavigateAssist()
      this.$nextTick(() => {
        this.state = {
          ...this.state,
          currentData: data,
          currentView: view,
          floors: [floorTree],
          domains: [domainTree]
        }
      })
      this.openModelData(data, view)
      this.bindEvent(this)
    },
    // 数据回调之后, 更新进度条
    updateDataNode(type, value) {
      if (isNaN(value)) {
        this.visibleState.isEmpty = true
        this.setState({
          loading: false,
          percent: 0
        })
        this.$message.warning('模型文件异常')
        return
      }
      if (type === 1 || type === window.WIND.CallbackType.DATALOAD_GEOMETRY_CHANGED) {
        // 模型加载百分比回调
        let percentNum = Math.min(100, Math.max(0, Math.floor(value))) || 0
        if (percentNum >= 0 && percentNum < 100) {
          this.setState({
            loading: true,
            percent: percentNum
          })
        } else {
          this.setState({
            loading: false
          })
          setTimeout(() => {
            this.showPushPin && this.initPushPin() // 延时之后显示图钉
          }, 2000)
        }
      }
    },
    // 图形回调之后, 更新显示控制树
    updateTreeNode(type, option) {
      this.loadingState.updateTree = true
      if (type === window.WIND.CallbackType.DISPLAYTREE_UPDATED || type === window.WIND.CallbackType.DISPLAYTREE_CREATED) {
        if (option) {
          let nodes = [],nodesObj = [];
          // 遍历option，更新每个节点的pick状态
          let traverseChildren = (children) => {
            for (let i = 0; i < children.length; i++) {
              // 1: 不选 2: 半选 3: 选择
              if (children[i].state === 3) {
                nodes.push(children[i].id)
                nodesObj.push({id:children[i].id,name:children[i].name}) 
              }
              traverseChildren(children[i].children)
            }
          }
          traverseChildren(option.children)
          if (option.YZTreeType === FLOOR_TREE) {
            this.setState({ selectedFloors: nodes })
            this.selectedFloorsObj = nodesObj
          } else if (option.YZTreeType === DOMAIN_TREE) {
            this.setState({ selectedDomains: nodes })
            this.setState({ selectedFloorsObj: nodesObj })
          }
        }
      } else if (type === window.WIND.CallbackType.WEBGLCONTEXT_LOST) {
        this.setState({
          loadFailedVisible: true
        })
      }
      this.$nextTick(() => {
        this.loadingState.updateTree = false
        this.highlightNodeByIds(this.highLightList)
      })

    },
    getCurrentViewData(type, option) {
      //点击监听右键菜单 ( fix右键模型拖拽出现菜单bug )
      if (type === window.WIND.CallbackType.RIGHTMOUSE_CLICKED) {
        this.visibleState.contextMenu = true
      }

      let key = 'floors'
      switch (option.YZTreeType) {
        case FLOOR_TREE:
          key = 'floors'
          break
        case DOMAIN_TREE:
          key = 'domains'
          break
      }
      if (type === 21) {
        this.setState({ [key]: option })
      }
    },

    // 打开模型
    async openModelData(data, view) {
      if (!this.modelList?.length && this.modelId && !this.isInitedVersion) {
        // 只需要初始化最新版本一次即可，使用isInitedVersion标识
        const [err, res] = await getHistory({ modelId: this.modelId })
        if (!err) {
          this.modelVersion = (res.data && res.data.version) || '1'
          this.isInitedVersion = true
        }
      }

      if (!this.modelList?.length) {
        getFloorsList({
          modelId:this.modelId, version: this.modelVersion
        }).then(res=>{
          this.originFloor = res.data
        })
        getDominsList({
          modelId:this.modelId,
          version: this.modelVersion,
          property: false
        }).then(res=>{
          this.originDomins = res.data
        })
        await data.getWINDDataLoader().openModelData(this.modelId, this.modelVersion) //打开对应模型id的模型数据
      } else {
        getFloorsList(this.modelList[0]).then(res=>{
          this.originFloor = res.data
        })
        getDominsList({
         ...this.modelList[0],
          property: false
        }).then(res=>{
          this.originDomins = res.data
        })
        await data.getWINDDataLoader().openModelDatas(this.modelList)
      }
     await data.getWINDDataLoader().openModelParameter() //打开模型属性
      let isLightShadowOpened = view.getWINDViewSetting().isLightShadowOpened()
      let isRealModeOpened = view.getWINDViewSetting().isLightShadowOpened()
      let isWireframeOpened = view.getWINDViewSetting().isWireframeOpened()

      //默认打开真实
      if (!isRealModeOpened) {
        view.getWINDViewSetting().isRealModeOpened(true)
      }
      //默认打开线框
      if (!isWireframeOpened) {
        view.getWINDViewSetting().isWireframeOpened(true)
      }
      this.isModelParameterLoaded = true;
      //派发一个事件
      this.$emit('modelParameterLoaded', true)
      this.setState({
        setParms: {
          currentColor: 'white',
          colors: [],
          lightVisible: isLightShadowOpened,
          realityVisible: true,
          wareVisible: true
        }
      })
    },
    /**
     * 绑定各类事件
     */
    bindEvent(context) {
      const canvasDiv = document.querySelector('.lay-wrap')
      const tabLayer = document.querySelector('.layout')

      if (canvasDiv) {
        let startTime
        let endTime
        const tabLayerContextMenuFn = (e) => {
          e.preventDefault()
        }
        tabLayer.addEventListener('contextmenu', tabLayerContextMenuFn)

        const canvasDivContextmenuFn = (e) => {
          e.preventDefault()
          context.selectEntries()
        }
        canvasDiv.addEventListener('contextmenu', canvasDivContextmenuFn)

        const canvasDivClickFn = (e) => {
          context.selectEntries()
          context.showPushPin && context.revertPushpin(context.pushpinList) // 还原图钉
          context.visibleState.contextMenu = false
        }
        canvasDiv.addEventListener('click', canvasDivClickFn, false)

        //移动端touchend 触摸监听
        const canvasDivTouchendFn = (e) => {
          e.preventDefault()
          context.selectEntries()
        }
        canvasDiv.addEventListener('touchend', canvasDivTouchendFn, false)

        const canvasDivMousedownFn = (e) => {
          startTime = Date.now()
          if (e.button === 2) {
            context.visibleState.contextMenu = false
          }
        }
        canvasDiv.addEventListener('mousedown', canvasDivMousedownFn)

        const canvasDivMouseupFn = (e) => {
          endTime = Date.now()
          if (e.button === 2) {
            if (endTime - startTime > 200) {
              context.visibleState.contextMenu = false
            } else {
              const { offsetX, offsetY } = e
              this.menuPosition = { pageX: offsetX, pageY: offsetY }
              this.visibleState.contextMenu = true
            }
          }
        }
        canvasDiv.addEventListener('mouseup', canvasDivMouseupFn)
        this.$once('hook:beforeDestroy', () => {
          tabLayer.removeEventListener('contextmenu', tabLayerContextMenuFn)
          canvasDiv.removeEventListener('contextmenu', canvasDivContextmenuFn)
          canvasDiv.removeEventListener('click', canvasDivClickFn)
          canvasDiv.removeEventListener('touchend', canvasDivTouchendFn)
          canvasDiv.removeEventListener('mousedown', canvasDivMousedownFn)
          canvasDiv.removeEventListener('mouseup', canvasDivMouseupFn)
        })
      }
    },
    /**
     * 获取选中实体
     */
     async selectEntries() {
      const { currentView } = this.state
      if (currentView) {
        const entities = currentView.getWINDViewRoaming().getSelectEntities()
        const uuid = entities[0] // 获取第一个选中的构件

        console.log('获取选中实体')
        if (uuid) {
          this.setState({ uuid })
        }
        if (entities) {
          this.setState({ entities })
        }
        return entities
      }
      return []
    },
    // 获取选中实体
    async selectJuging() {
      try {
        const { currentView, currentData } = this.state;
        console.log(currentView)
        let entities = [];
        if (currentView) {
          console.log('进来了')
          // entities = currentView.getWINDViewRoaming().handleRightclick();
          entities = currentView.getWINDViewRoaming().getSelectEntities();
        }
        console.log('获取选中实例数据', entities);
        this.state = {
          ...this.state,
          selectEntities: entities,
        };
        const allRequest = []
        entities.forEach((item) => {
          allRequest.push(currentData.getWINDDataQuerier().getEntityParameterL(item))
        })
        console.log('指定模块', allRequest);
        const resList = await Promise.all(allRequest) // 获取选中构件的实体信息
        const result = []
        console.log('获取选中构件信息', resList);
        if(!resList.length){
          this.$message.warning('请先选中所要关联模型');
        }
        resList.forEach(item => {
          result.push(item)
        })
        console.log(result)
        return result;
        
      } catch(e){
        return Promise.reject(e)
      }
    },
    // 开启关闭剖切盒
    switchCube() {
      const { currentView } = this.state
      const sectionState = currentView.getWINDViewSection().getSectionState()
      if (sectionState._cubeSectionOpened) {
        currentView.getWINDViewSection().closeCubeSection()
      } else {
        currentView.getWINDViewSection().openCubeSection()
      }
    },

    // 开启关闭测量
    switchMeasure(value) {
      const { currentView } = this.state
      const measureState = currentView.getWINDViewMeasure().getMeasureState()
      if (measureState._measureOpened) {
        currentView.getWINDViewMeasure().closeMeasure()
        currentView.getWINDViewMeasure().finishMeasure()
      } else {
        currentView.getWINDViewMeasure().openMeasure()
        currentView.getWINDViewMeasure().setMeasureType(window.WIND.MeasureType.DOT)
      }
    },

    // 选择测量
    onClickMeasure(key) {
      const { currentView } = this.state
      const measureState = currentView.getWINDViewMeasure().getMeasureState() //获取测量状态
      if (!measureState._measureOpened) {
        return currentView.getWINDViewMeasure().openMeasure()
      } else {
        switch (key) {
          case 'view':
            currentView.getWINDViewMeasure().setMeasureType(window.WIND.MeasureType.VIEW)
            break
          case 'dot':
            currentView.getWINDViewMeasure().setMeasureType(window.WIND.MeasureType.DOT)
            break
          case 'distance':
            currentView.getWINDViewMeasure().setMeasureType(window.WIND.MeasureType.DISTANCE)
            break
          case 'angle':
            currentView.getWINDViewMeasure().setMeasureType(window.WIND.MeasureType.ANGLE)
            break
          case 'length':
            currentView.getWINDViewMeasure().setMeasureType(window.WIND.MeasureType.LENGTH)
            break
          default:
            currentView.getWINDViewMeasure().setMeasureType(window.WIND.MeasureType.VIEW)
            break
        }
      }
    },

    // 开启关闭漫游
    switchRoaming() {
      const { currentView } = this.state
      const { _thirdPersonOpened, _gravityFallOpened, _collisionDectectOpened, _personRoamingOpened } = currentView.getWINDViewRoaming().getRoamingState()
      if (_personRoamingOpened) {
        // 如果已开启漫游，先关闭各项已开启的子功能，再关闭漫游
        _thirdPersonOpened && this.onClickRoam('third')
        _gravityFallOpened && this.onClickRoam('gravity')
        _collisionDectectOpened && this.onClickRoam('crash')
        currentView.getWINDViewRoaming().closePersonRoaming()
        currentView.getWINDViewRoaming().revertHomePosition()
      } else {
        currentView.getWINDViewRoaming().setCharacterResource(characterdat, characterpng)
        currentView.getWINDViewRoaming().openPersonRoaming()
      }
    },

    // 点击选择漫游模式
    onClickRoam(key) {
      const { currentView } = this.state
      const status = currentView.getWINDViewRoaming().getRoamingState()
      switch (key) {
        case 'third':
          currentView.getWINDViewRoaming().isThirdPersonOpened(!status._thirdPersonOpened)
          break
        case 'gravity':
          currentView.getWINDViewRoaming().isGravityFallOpened(!status._gravityFallOpened)
          break
        case 'crash':
          currentView.getWINDViewRoaming().isCollisionDetectOpened(!status._collisionDectectOpened)
          break
        default:
          currentView.getWINDViewRoaming().isGravityFallOpened(!status._gravityFallOpened)
          break
      }
    },
    /**
     * 更新漫游速度
     */
    updateRoamingSpeed(val) {
      const { currentView } = this.state
      const speedNum = val
      const reg = /^[0-9]*$/

      if (speedNum && speedNum !== 0 && reg.test(speedNum)) {
        this.setState({ roamSpeed: speedNum })
        currentView.getWINDViewRoaming().setCharacterMoveSpeed(speedNum)
      }
    },
    /**
     * 切换小地图显示
     */
    switchMap() {
      const { currentView } = this.state
      const mapState = currentView.getWINDViewAssist().getAssistState()
      if (mapState && mapState._minimapOpened) {
        currentView.getWINDViewAssist().closeMinimapAssist()
      } else {
        //设置地图属性
        const property = {
          x: 32, //起始水平位置
          y: 50, //起始垂直位置
          width: 300, //宽度
          height: 200, //高度
          backgroundColor: [229, 231, 235, 1] //背景色
        }
        currentView.getWINDViewAssist().openMinimapAssist()
        currentView.getWINDViewAssist().setMinimapProperty(property)
      }
    },
    /**
     * 设置光照、线框、真实、背景颜色
     * @param {Object} setParms -设置参数
     */
    onClickSetting(setParms) {
      const { currentView } = this.state
      // 背景色
      const selectedColors = setParms && setParms.colors
      if (selectedColors && selectedColors.length > 1) {
        let topColor = selectedColors && selectedColors[0].topColor
        let bottomColor = selectedColors && selectedColors[1].bottomColor
        // (渐变色)
        currentView.getWINDViewSetting().setBackgroundGradientTopColor(topColor[0], topColor[1], topColor[2])
        currentView.getWINDViewSetting().setBackgroundGradientBottomColor(bottomColor[0], bottomColor[1], bottomColor[2])
        currentView.getWINDViewSetting().setBackgroundType(2)
      } else if (selectedColors && selectedColors.length === 1) {
        // (纯色)
        let colors = selectedColors && selectedColors[0].colorRGB
        currentView.getWINDViewSetting().setBackgroundPureColor(colors[0], colors[1], colors[2], colors[3])
        currentView.getWINDViewSetting().setBackgroundType(1)
      }

      // 光照
      let lightVisible = setParms && setParms.lightVisible
      currentView.getWINDViewSetting().isLightShadowOpened(lightVisible)
      // 真实
      let realityVisible = setParms && setParms.realityVisible
      currentView.getWINDViewSetting().isRealModeOpened(realityVisible)
      // 线框
      let wareVisible = setParms && setParms.wareVisible
      currentView.getWINDViewSetting().isWireframeOpened(wareVisible)

      this.setState({
        setParms
      })
      this.updateVisible('settingVisible', false)
    },
    /**
     * 返回主视角(复位相机)
     */
    mainView() {
      const { currentView, pushpin } = this.state
      currentView.getWINDViewRoaming().revertHomePosition()
      this.unHighlightTreeNode()
      this.revertPushpin(this.pushpinList) // 还原图钉的状态
    },

    // 刷新操作，重置所有内容
    handleRefresh() {
      this.$emit('refresh')
      this.loadModel()
    },
    /**
     * 点击树节点显示隐藏构件
     */
    showCurSelectTreeNode(record, type) {
      const { currentView, floor, domains } = this.state
      if (currentView) {
        currentView.getWINDViewControl().displayTreeNode(record.id, type === 1 ? floor : domains)
      }
    },
    /**
     * 点击显示高亮构件
     * @param {Number|String} id -树节点在树结构中的ID
     * @param {Boolean} untransparent -是否透明所有构件
     */
    highlightTreeNode(id, untransparent = false) {
      const { currentView, currentData } = this.state
      console.log(id)
      console.log('显示高亮数据', this.state)
      if (currentView && id) {
        currentView.getWINDViewControl().unhighlightAllEntities()
        currentView.getWINDViewControl().highlightTreeNode(id)
        !untransparent && currentView.getWINDViewControl().transparentAllComponents() // 在highlightTreeNode之后调用，否则highlightTreeNode会失效
        currentView.getWINDViewRoaming().locateSelectEntities()
      }
    },
    /**
     * 点击取消显示高亮
     */
    unHighlightTreeNode() {
      const { currentView } = this.state
      currentView.getWINDViewControl().untransparentAllComponents()
      currentView.getWINDViewControl().unhighlightAllEntities()
      currentView.getWINDViewRoaming().revertHomePosition()
    },
    /**
     * toolbar点击事件
     * @param {String} funcName -菜单key值
     */
    selectMenu(funcName) {
      switch (funcName) {
        case 'mainView':
          this.mainView()
          break
        case 'refresh':
          this.handleRefresh()
          break
        case 'sectioning':
          this.switchCube()
          break
        case 'measure':
          this.switchMeasure()
          break
        case 'roaming':
          this.switchRoaming()
          break
        case 'miniMap':
          this.switchMap()
          break
        case 'setting':
          this.updateVisible('settingVisible', true, true)
          break
        case 'attr':
          this.updateVisible('attrVisible', true, true)
          break
        case 'version':
          this.updateVisible('versionVisible', true)
          break
        case 'search':
          this.updateVisible('searchVisible', true)
          break
        case 'switchModel':
          this.$emit('model:switch')
          break
        case 'test':
          this.handleTest()
          break
        case 'share':
          this.updateVisible('shareVisible', true, true)
        default:
          this.mainView()
          break
      }
    }
  }
}
</script>

<style lang="less" scoped>
.BimIntegrate-container {
  height: 100%;
  position: relative;
  .layout-loading-process {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 10%;
    height: 10%;
    transform: translate(-50%, -50%);
    z-index: 98;
  }
  .empty-container {
    width: 100%;
    height: 100%;
    background-color: #ffffff;
    display: flex;
    justify-content: center;
    align-items: center;
  }
  .layout-container {
    width: 100%;
    height: 100%;
    position: relative;
  }
  .tool-bar {
    width: fit-content;
    height: fit-content;
    background-color: #ffffff;
    border-radius: 4px;
    position: absolute;
    left: 50%;
    top: 0;
    transform: translate(-50%, 0);
  }
  .extra-wrapper {
    position: absolute;
    right: 0;
    bottom: 0;
    display: flex;
    align-items: center;
    .roaming-speed-wrapper {
      display: flex;
      align-items: center;
      .speed-label {
        margin-right: 15px;
      }
      .speed-value {
        width: 100px;
      }
    }
  }
  .side-bottom {
    width: 90%;
    height: 40%;
    margin: 12px auto;
    box-shadow: -2px -2px 4px rgba(225, 225, 225, 1), 2px 2px 4px rgba(225, 225, 225, 1);
    border-radius: 5px;
    position: relative;
  }
  .side-left {
    height: 100%;
    position: absolute;
    left: 0;
    top: 0;
    .left-layer {
      height: 100%;
      display: flex;
      flex-direction: column;
      justify-content: center;
    }
  }
  .side-right {
    position: absolute;
    top: 0;
    right: 0;
  }
  .context-menu-container {
    position: absolute;
    top: 0;
    left: 0;
    background-color: rgba(0, 0, 0, 1);
    opacity: 0.7;
    color: #ffffff;
    .ant-menu-item {
      height: 30px;
      line-height: 30px;
    }
  }
}
</style>
<style lang="less">
.contextSubmenu {
  opacity: 0.7;
  .ant-menu {
    color: #ffffff;
    background-color: rgba(0, 0, 0, 1);
    .ant-menu-item {
      height: 30px;
      line-height: 30px;
    }
  }
}
  .thumbtackImg {
    position: absolute;
    right: 50px;
    top: 50%;
    height: 60px;
    width: auto;
    cursor: pointer;
  }
</style>
